/**
 * 
 */
package com.appwx.sdk.refreshlistview;

import com.appwx.sdk.R;
import com.appwx.sdk.app.AppLoger;
import com.appwx.sdk.app.AppToast;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.GradientDrawable.Orientation;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
import android.view.animation.RotateAnimation;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;

/**
 * @author xiajun
 *
 */
public class PullRefreshLinearLayout extends LinearLayout implements OnTouchListener{

	public static final String TAG = PullRefreshLinearLayout.class.getSimpleName();
	
	public static final int VIEW_TYPE_LISTVIEW = 0x00001;
	
	public static final int VIEW_TYPE_SCROLLVIEW = 0x00002;
	
	public static final int VIEW_TYPE_GRIDVIEW = 0x00003;
	/**
	 * 下拉状态
	 */
	public static final int STATUS_PULL_TO_REFRESH = 0;

	/**
	 * 释放立即刷新状态
	 */
	public static final int STATUS_RELEASE_TO_REFRESH = 1;

	/**
	 * 正在刷新状态
	 */
	public static final int STATUS_REFRESHING = 2;

	/**
	 * 刷新完成或未刷新状态
	 */
	public static final int STATUS_REFRESH_FINISHED = 3;

	/**
	 * 下拉头部回滚的速度
	 */
	public static final int SCROLL_SPEED = -20;
	
	
	/**
	 * 一分钟的毫秒值，用于判断上次的更新时间
	 */
	public static final long ONE_MINUTE = 60 * 1000;

	/**
	 * 一小时的毫秒值，用于判断上次的更新时间
	 */
	public static final long ONE_HOUR = 60 * ONE_MINUTE;

	/**
	 * 一天的毫秒值，用于判断上次的更新时间
	 */
	public static final long ONE_DAY = 24 * ONE_HOUR;

	/**
	 * 一月的毫秒值，用于判断上次的更新时间
	 */
	public static final long ONE_MONTH = 30 * ONE_DAY;

	/**
	 * 一年的毫秒值，用于判断上次的更新时间
	 */
	public static final long ONE_YEAR = 12 * ONE_MONTH;
	
	/**
	 * 上次更新时间的字符串常量，用于作为SharedPreferences的键值
	 */
	private static final String UPDATED_AT = "updated_at";
	
	
	private View parent = null;
	
	/**
	 * 下拉刷新头视图
	 */
	private View mHeader;
	
	/**
	 * 刷新时显示的进度条
	 */
	private ProgressBar mProgressBar;

	/**
	 * 指示下拉和释放的箭头
	 */
	private ImageView mArrow;

	/**
	 * 指示下拉和释放的文字描述
	 */
	private TextView mDescription;

	/**
	 * 上次更新时间的文字描述
	 */
	private TextView mUpdateAt;
	
	/**
	 * 需要去下拉刷新的ListView
	 */
	private ListView mListView;
	
	/**
	 * 需要去下拉刷新的ScrollView
	 */
	private ScrollView mScrollView;
	
	/**
	 * 需要去下拉刷新的GridView
	 */
	private GridView mGridView;
	
	/**
	 * 是否已加载过一次layout，这里onLayout中的初始化只需加载一次
	 */
	private boolean mLoadOnce;
	
	/**
	 * 当前是否可以下拉，只有ListView滚动到头的时候才允许下拉
	 */
	private boolean ableToPull;
	
	/**
	 * 手指按下时的屏幕纵坐标
	 */
	private float mDownY;
	
	/**
	 * 当前处理什么状态，可选值有
	 * STATUS_PULL_TO_REFRESH, 
	 * STATUS_RELEASE_TO_REFRESH,
	 * STATUS_REFRESHING,
	 * STATUS_REFRESH_FINISHED
	 */
	private int currentStatus = STATUS_REFRESH_FINISHED;;

	/**
	 * 记录上一次的状态是什么，避免进行重复操作
	 */
	private int lastStatus = currentStatus;
	
	/**
	 * 下拉头的高度
	 */
	private int mHideHeaderHeight;
	
	/**
	 * 在被判定为滚动之前用户手指可以移动的最大值(获取用户没有在触摸滚动前最大移动范围)。
	 */
	private int mTouchSlop;
	
	/**
	 * 为了防止不同界面的下拉刷新在上次更新时间上互相有冲突，使用id来做区分
	 */
	private int mId = -1;
	
	private int mTag;
	
	/**
	 * 最后一次更新时间的毫秒值
	 */
	private long mLastUpdateTime;
	
	/**
	 * 视图刷新回调接口
	 */
	private ViewRefreshListener mListener;
	
	/**
	 * 用于存储上次更新时间
	 */
	private SharedPreferences mPreferences;
	
	/**
	 * 下拉头的布局参数
	 */
	private MarginLayoutParams mHeaderLayoutParams;
	

	
	
	/**
	 * 视图监听接口
	 * @author xiajun
	 */
	public interface ViewRefreshListener{
		void onRefresh();
	}
	
	/**
	 * 下拉刷新控件的构造函数，会在运行时动态添加一个下拉头的布局。
	 * @param context
	 * @param attrs
	 */
	public PullRefreshLinearLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
		mHeader = LayoutInflater.from(context).inflate(R.layout.pull_refresh_linearlayout_head, null, true);
		mProgressBar = (ProgressBar) mHeader.findViewById(R.id.progress_bar);
		mArrow = (ImageView) mHeader.findViewById(R.id.arrow);
		mDescription = (TextView) mHeader.findViewById(R.id.description);
		mUpdateAt = (TextView) mHeader.findViewById(R.id.updated_at);
		mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
		
		refreshUpdatedAtValue();
		setOrientation(VERTICAL);
		addView(mHeader, 0);
		
	}
	
	public void setmTag(int tag){
		this.mTag = tag;
	}

	/**
	 * 注册视图监听
	 * @param listener 监听器
	 * @param id 为了防止不同界面的下拉刷新在上次更新时间上互相有冲突， 请不同界面在注册下拉刷新监听器时一定要传入不同的id。(标识ID)
	 */
	public void setViewRefreshListener(ViewRefreshListener listener,int id){
		mListener = listener;
		mId = id;
	}
	
	/**
	 * 完成刷新,重置视图
	 */
	public void finishRefreshing(){
		currentStatus = STATUS_REFRESH_FINISHED;
		mPreferences.edit().putLong(UPDATED_AT + mId, System.currentTimeMillis()).commit();
		new HideHeaderTask().execute();
	}
	
	/**
	 * 根据当前ListView的滚动状态来设定 {@link #ableToPull}
	 * 的值，每次都需要在onTouch中第一个执行，这样可以判断出当前应该是滚动ListView，还是应该进行下拉。
	 * @param event
	 */
	private void setIsAbleToPull(MotionEvent event) {
		View firstChild = null;
		if(mTag == VIEW_TYPE_LISTVIEW){
			firstChild = mListView.getChildAt(0);
			if(firstChild != null){
				int firstVisiblePosition = mListView.getFirstVisiblePosition();
				if(firstVisiblePosition == 0 && firstChild.getTop() == 0){
					if(!ableToPull){
						mDownY = event.getRawY();
					}
					ableToPull = true;
				}else{
					//如果头布局的最顶部!=隐藏的高度
					if(mHeaderLayoutParams.topMargin != mHideHeaderHeight){
						mHeaderLayoutParams.topMargin = mHideHeaderHeight;
						mHeader.setLayoutParams(mHeaderLayoutParams);
					}
					ableToPull = false;
				}
			}else{
				ableToPull = true;
			}
		}else if (mTag == VIEW_TYPE_SCROLLVIEW){
			firstChild = mScrollView.getChildAt(0);
			if(firstChild != null){
				if(firstChild.getTop() == 0 && firstChild.getPaddingTop() == 0){
					if(!ableToPull){
						mDownY = event.getRawY();
					}
					ableToPull = true;
				}else{
					//如果头布局的最顶部!=隐藏的高度
					if(mHeaderLayoutParams.topMargin != mHideHeaderHeight){
						mHeaderLayoutParams.topMargin = mHideHeaderHeight;
						mHeader.setLayoutParams(mHeaderLayoutParams);
					}
					ableToPull = false;
				}
			}else{
				ableToPull = true;
			}
		}else if (mTag == VIEW_TYPE_GRIDVIEW){
			firstChild = mGridView.getChildAt(0);
			if(firstChild != null){
				if(firstChild.getTop() == 0 && firstChild.getPaddingTop() == 0){
					if(!ableToPull){
						mDownY = event.getRawY();
					}
					ableToPull = true;
				}else{
					//如果头布局的最顶部!=隐藏的高度
					if(mHeaderLayoutParams.topMargin != mHideHeaderHeight){
						mHeaderLayoutParams.topMargin = mHideHeaderHeight;
						mHeader.setLayoutParams(mHeaderLayoutParams);
					}
					ableToPull = false;
				}
			}else{
				ableToPull = true;
			}
		}
		
		
		
		/*View firstChild = mListView.getChildAt(0);
		if(firstChild != null){
			int firstVisiblePosition = mListView.getFirstVisiblePosition();
			// 如果首个元素的上边缘，距离父布局值为0，就说明ListView滚动到了最顶部，此时应该允许下拉刷新
			if(firstVisiblePosition == 0 && firstChild.getTop() == 0){
				if(!ableToPull){
					mDownY = event.getRawY();
				}
				ableToPull = true;
			}else{
				//如果头布局的最顶部!=隐藏的高度
				if(mHeaderLayoutParams.topMargin != mHideHeaderHeight){
					mHeaderLayoutParams.topMargin = mHideHeaderHeight;
					mHeader.setLayoutParams(mHeaderLayoutParams);
				}
				ableToPull = false;
			}
		}else{
			//如果ListView中没有元素，也应该允许下拉刷新
			ableToPull = true;
		}*/
	}
	
	/**
	 * 更新下拉头中的信息
	 */
	private void updateHeaderView() {
		if(lastStatus != currentStatus){
			if(currentStatus == STATUS_PULL_TO_REFRESH){
				mDescription.setText(getResources().getString(R.string.pull_to_linearlayout_refresh));
				mArrow.setVisibility(View.VISIBLE);
				mProgressBar.setVisibility(View.GONE);
				rotateArrow();
			}else if(currentStatus == STATUS_RELEASE_TO_REFRESH){
				mDescription.setText(getResources().getString(R.string.release_to_refresh));
				mArrow.setVisibility(View.VISIBLE);
				mProgressBar.setVisibility(View.GONE);
				rotateArrow();
			}else if(currentStatus == STATUS_REFRESHING){
				mDescription.setText(getResources().getString(R.string.refreshing));
				mProgressBar.setVisibility(View.VISIBLE);
				mArrow.setVisibility(View.GONE);
				mArrow.clearAnimation();
			}
			refreshUpdatedAtValue();
		}
	}
	
	/**
	 * 根据当前的状态来旋转箭头。
	 */
	private void rotateArrow() {
		float pivotX = mArrow.getWidth() / 2f;
		float pivotY = mArrow.getHeight() / 2f;
		float fromDegrees = 0f;
		float toDegrees = 0f;
		if(currentStatus == STATUS_PULL_TO_REFRESH){
			fromDegrees = 180f;
			toDegrees = 360f;
		}else if(currentStatus == STATUS_RELEASE_TO_REFRESH){
			fromDegrees = 0f;
			toDegrees = 180f;
		}
		
		RotateAnimation animation = new RotateAnimation(fromDegrees, toDegrees,pivotX, pivotY);
		animation.setDuration(100);
		animation.setFillAfter(true);
		mArrow.setAnimation(animation);
	}
	
	/**
	 * 刷新下拉头中上次更新时间的文字描述。
	 */
	private void refreshUpdatedAtValue() {
		mLastUpdateTime = mPreferences.getLong(UPDATED_AT + mId, -1);
		long currentTime = System.currentTimeMillis();
		long timePassed = currentTime - mLastUpdateTime;
		long timeIntoFormat;
		String updateAtValue;
		if(mLastUpdateTime == -1){
			updateAtValue = getResources().getString(R.string.not_updated_yet);
		}else if(timePassed <0){
			updateAtValue = getResources().getString(R.string.time_error);
		}else if (timePassed < ONE_MINUTE) {
			updateAtValue = getResources().getString(R.string.updated_just_now);
		} else if (timePassed < ONE_HOUR) {
			timeIntoFormat = timePassed / ONE_MINUTE;
			String value = timeIntoFormat + "分钟";
			updateAtValue = String.format(getResources().getString(R.string.updated_at), value);
		} else if (timePassed < ONE_DAY) {
			timeIntoFormat = timePassed / ONE_HOUR;
			String value = timeIntoFormat + "小时";
			updateAtValue = String.format(getResources().getString(R.string.updated_at), value);
		} else if (timePassed < ONE_MONTH) {
			timeIntoFormat = timePassed / ONE_DAY;
			String value = timeIntoFormat + "天";
			updateAtValue = String.format(getResources().getString(R.string.updated_at), value);
		} else if (timePassed < ONE_YEAR) {
			timeIntoFormat = timePassed / ONE_MONTH;
			String value = timeIntoFormat + "个月";
			updateAtValue = String.format(getResources().getString(R.string.updated_at), value);
		} else {
			timeIntoFormat = timePassed / ONE_YEAR;
			String value = timeIntoFormat + "年";
			updateAtValue = String.format(getResources().getString(R.string.updated_at), value);
		}
		mUpdateAt.setText(updateAtValue);
	}
	
	/**
	 * 使当前线程睡眠指定的毫秒数。
	 * @param time 指定当前线程睡眠多久，以毫秒为单位
	 */
	private void sleep(int time) {
		try {
			Thread.sleep(time);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 正在刷新的任务，在此任务中会去回调注册进来的下拉刷新监听器。
	 */
	class RefreshingTask extends AsyncTask<Void, Integer, Void> {

		@Override
		protected Void doInBackground(Void... params) {
			int topMargin = mHeaderLayoutParams.topMargin;
			while (true) {
				topMargin = topMargin + SCROLL_SPEED;
				if (topMargin <= 0) {
					topMargin = 0;
					break;
				}
				publishProgress(topMargin);
				sleep(10);
			}
			currentStatus = STATUS_REFRESHING;
			publishProgress(0);
			if (mListener != null) {
				mListener.onRefresh();
			}
			return null;
		}
		
		@Override
		protected void onProgressUpdate(Integer... topMargin) {
			updateHeaderView();
			mHeaderLayoutParams.topMargin = topMargin[0];
			mHeader.setLayoutParams(mHeaderLayoutParams);
		}
		
	}
	
	/**
	 * 隐藏下拉头的任务，当未进行下拉刷新或下拉刷新完成后，此任务将会使下拉头重新隐藏。
	 * 
	 * @author guolin
	 */
	class HideHeaderTask extends AsyncTask<Void, Integer, Integer> {

		@Override
		protected Integer doInBackground(Void... params) {
			int topMargin = mHeaderLayoutParams.topMargin;
			while (true) {
				topMargin = topMargin + SCROLL_SPEED;
				if (topMargin <= mHideHeaderHeight) {
					topMargin = mHideHeaderHeight;
					break;
				}
				publishProgress(topMargin);
				sleep(10);
			}
			return topMargin;
		}
		
		@Override
		protected void onProgressUpdate(Integer... topMargin) {
			mHeaderLayoutParams.topMargin = topMargin[0];
			mHeader.setLayoutParams(mHeaderLayoutParams);
		}

		@Override
		protected void onPostExecute(Integer topMargin) {
			mHeaderLayoutParams.topMargin = topMargin;
			mHeader.setLayoutParams(mHeaderLayoutParams);
			currentStatus = STATUS_REFRESH_FINISHED;
		}
		
	}
	
	
	/**
	 * 当ListView被触摸时调用，其中处理了各种下拉刷新的具体逻辑。
	 */
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		setIsAbleToPull(event);
		if(ableToPull){
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				mDownY = event.getRawY();
				break;
			case MotionEvent.ACTION_MOVE:
				
				if(mTag == VIEW_TYPE_SCROLLVIEW){
					
					if (v.getScrollY() <= 0) {
						float mMoveY = event.getRawY();
						int mDistance = (int)(mMoveY - mDownY);//得到拉动距离
						//如果距离为0并且头视图最顶部<=隐藏视图的高度,就关闭下拉事件
						if(mDistance <=0 && mHeaderLayoutParams.topMargin <= mHideHeaderHeight){
							return false;
						}
						
						if(mDistance < mTouchSlop){
							return false;
						}
						
						if(currentStatus != STATUS_REFRESHING){
							if(mHeaderLayoutParams.topMargin > 0){
								currentStatus = STATUS_RELEASE_TO_REFRESH;
							}else{
								currentStatus = STATUS_PULL_TO_REFRESH;
							}
							//通过偏移下拉头的topMargin值，来实现下拉效果
							mHeaderLayoutParams.topMargin = (mDistance / 2) + mHideHeaderHeight;
							mHeader.setLayoutParams(mHeaderLayoutParams);
						}
						
						AppLoger.info(TAG, "ScrollView 到顶了");
						mScrollView.requestDisallowInterceptTouchEvent(false);
					} else if (mScrollView.getChildAt(0).getMeasuredHeight() <= v.getHeight() + v.getScrollY()) {
						AppLoger.info(TAG,"ScrollView 到底了");
						mScrollView.requestDisallowInterceptTouchEvent(true);
					}
				}else{
					float mMoveY = event.getRawY();
					int mDistance = (int)(mMoveY - mDownY);//得到拉动距离
					//如果距离为0并且头视图最顶部<=隐藏视图的高度,就关闭下拉事件
					if(mDistance <=0 && mHeaderLayoutParams.topMargin <= mHideHeaderHeight){
						return false;
					}
					
					if(mDistance < mTouchSlop){
						return false;
					}
					
					if(currentStatus != STATUS_REFRESHING){
						if(mHeaderLayoutParams.topMargin > 0){
							currentStatus = STATUS_RELEASE_TO_REFRESH;
						}else{
							currentStatus = STATUS_PULL_TO_REFRESH;
						}
						//通过偏移下拉头的topMargin值，来实现下拉效果
						mHeaderLayoutParams.topMargin = (mDistance / 2) + mHideHeaderHeight;
						mHeader.setLayoutParams(mHeaderLayoutParams);
					}
				}
				
				break;
			default:
				if(currentStatus == STATUS_RELEASE_TO_REFRESH){
					//当前状态==释放立即刷新状态，调用正在刷新的任务
					new RefreshingTask().execute();
				}else if(currentStatus == STATUS_PULL_TO_REFRESH){
					//当前状态==下拉状态，调用隐藏下拉头的任务
					new HideHeaderTask().execute();
				}
				break;
			}
			/**
			 * 当前状态 ==下拉状态 或者
			 * 当前状态 ==释放立即刷新状态
			 */
			if(currentStatus == STATUS_PULL_TO_REFRESH
					|| currentStatus == STATUS_RELEASE_TO_REFRESH){
				updateHeaderView();
				if(mTag == VIEW_TYPE_LISTVIEW){
					mListView.setFocusable(false);
					mListView.setPressed(false);
					mListView.setFocusableInTouchMode(false);
				}else if (mTag == VIEW_TYPE_SCROLLVIEW){
					mScrollView.setFocusable(false);
					mScrollView.setPressed(false);
					mScrollView.setFocusableInTouchMode(false);
					mScrollView.requestDisallowInterceptTouchEvent(false);
				}else if (mTag == VIEW_TYPE_GRIDVIEW){
					mGridView.setFocusable(false);
					mGridView.setPressed(false);
					mGridView.setFocusableInTouchMode(false);
				}
					
				
				lastStatus = currentStatus;
				// 当前正处于下拉或释放状态，通过返回true屏蔽掉ListView的滚动事件
				return true;
				
			}
		}
		return false;
	}
	
	/**
	 * 进行一些关键性的初始化操作，比如：将下拉头向上偏移进行隐藏，给ListView注册touch事件。
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		
		if(changed && !mLoadOnce){
			mHideHeaderHeight = -mHeader.getHeight();//设置头部视图高度负值
			mHeaderLayoutParams = (MarginLayoutParams) mHeader.getLayoutParams();
			mHeaderLayoutParams.topMargin = mHideHeaderHeight;
//			mListView = (ListView) getChildAt(1);//获取LinearLayout中第一个元素视图(ListView)
//			mListView.setOnTouchListener(this);
//			mLoadOnce = true;
			loadView();
		}
		
	}
	
	private void loadView(){
		int count = getChildCount();          
//        if (count < 3) {          
//        	//这种布局必须包含3个子视图,并且adapterview或scrollview必须在第二个位置
//            throw new IllegalArgumentException(          
//                    "this layout must contain 3 child views,and AdapterView or ScrollView must in the second position!");          
//        }  
        
        for (int i = 0; i < count; ++i) {
        	parent = getChildAt(i);
        	if(parent instanceof ListView){
        		AppLoger.error("ListView.....");
        		mListView = (ListView) getChildAt(1);
        		mListView.setOnTouchListener(this);
        	}else if (parent instanceof ScrollView){
        		AppLoger.error("ScrollView.....");
        		mScrollView = (ScrollView) getChildAt(1);
        		mScrollView.setOnTouchListener(this);
        	}else if (parent instanceof GridView){
        		AppLoger.error("GridView.....");
        		mGridView = (GridView) getChildAt(1);
        		mGridView.setOnTouchListener(this);
        	}
		}
        mLoadOnce = true;
        
	}
	
}
